package com.icow.wms.basic.utils;

import com.icow.wms.basic.domain.Door;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;

@SuppressWarnings("all")
@Slf4j
public class DoorHandler extends ChannelInboundHandlerAdapter {

    public static Map<String, Channel> IP_CHANNEL_MAP = new HashMap<>();

    public static Map<String, Door> IP_DOOR_MAP = new HashMap<>();

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        Channel inChannel = ctx.channel();
        String ip = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress().getHostAddress();
        //永远将最新的通道保存至MAP
        IP_CHANNEL_MAP.put(ip, inChannel);
        if (IP_DOOR_MAP.get(ip) == null) {
            IP_DOOR_MAP.put(ip, new Door(ip));
        }
        log.info("door client " + ctx.channel().remoteAddress() + " is active");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        String ip = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress().getHostAddress();
        IP_CHANNEL_MAP.remove(ip);
        ctx.close();
        log.info(ctx.channel().remoteAddress() + " inactive pipe close");
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        String ip = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress().getHostAddress();
        IP_CHANNEL_MAP.remove(ip);
        ctx.close();
        log.info(ctx.channel().remoteAddress() + " exception pipe close " + cause.getMessage());
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ByteBuf byteBuf = null;
        if (msg instanceof ByteBuf) {
            byteBuf = (ByteBuf) msg;
        }
        byte[] bytes = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(bytes);

        //log.info(Arrays.toString(bytes));
        String ip = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress().getHostAddress();
        Door door = IP_DOOR_MAP.get(ip);
        if (door == null) {
            log.info("door " + ip + " not online");
        }
        //0x 00 01 00 00 00 04 FF 02 01 03
        if (bytes.length == 10 && bytes[0] == 0 && bytes[1] == 1 && bytes[2] == 0 && bytes[3] == 0
                && bytes[4] == 0 && bytes[5] == 4 && bytes[6] == (byte) 255 && bytes[7] == 2 && bytes[8] == 1) {
            door.setDoorUpDI1(((bytes[9] >> 0) & 1) == 1);
            door.setDoorUpDI2(((bytes[9] >> 1) & 1) == 1);
            door.setDoorUpDI3(((bytes[9] >> 2) & 1) == 1);
            door.setDoorUpDI4(((bytes[9] >> 3) & 1) == 1);
            log.info("door " + ip + " DI1 " + door.isDoorUpDI1() + " DI2 " + door.isDoorUpDI2() + " DI3 " + door.isDoorUpDI3() + " DI4 " + door.isDoorUpDI4());
        }
        //Manual recycling to prevent memory leakage;
        ReferenceCountUtil.release(byteBuf);
    }


    public static byte[] getReadMsgForDoor() {
        byte[] doorData = new byte[12];
        doorData[0] = 0;
        doorData[1] = 1;
        doorData[2] = 0;
        doorData[3] = 0;
        doorData[4] = 0;
        doorData[5] = 6;
        doorData[6] = (byte) 255;
        doorData[7] = 2;
        doorData[8] = 0;
        doorData[9] = (byte) 200;
        doorData[10] = 0;
        doorData[11] = 4;
        return doorData;
    }


    public static byte[] getCmdMsgForDoor(String openDoorPipe, boolean openDoor) {
        byte[] doorData = new byte[12];
        doorData[0] = 0;
        doorData[1] = 1;
        doorData[2] = 0;
        doorData[3] = 0;
        doorData[4] = 0;
        doorData[5] = 6;
        doorData[6] = (byte) 255;
        doorData[7] = 5;
        doorData[8] = 0;
        if (Pipe.DO1.equals(openDoorPipe)) {
            doorData[9] = 100;
        } else if (Pipe.DO2.equals(openDoorPipe)) {
            doorData[9] = 101;
        } else if (Pipe.DO3.equals(openDoorPipe)) {
            doorData[9] = 102;
        } else if (Pipe.DO4.equals(openDoorPipe)) {
            doorData[9] = 103;
        }

        if (openDoor) {
            doorData[10] = (byte) 255;
            doorData[11] = 0;
        }
        return doorData;
    }

    public static boolean sendMsg(String ip, byte[] bytes) {
        if (IP_CHANNEL_MAP.containsKey(ip)) {
            Channel channel = IP_CHANNEL_MAP.get(ip);
            channel.writeAndFlush(Unpooled.wrappedBuffer(bytes));
            //log.info("向 " + ip + " 发送数据 " + Arrays.toString(bytes));
            return true;
        }
        log.info("send error not online " + ip);
        return false;

    }
}
